#pragma once

#include <vector>
#include <list>
#include "event_loop.h"
#include "net_callback.h"
#include "buffer.h"

namespace rr {
namespace nio {

struct WriteInfo {
    int32_t status = 0;
    char *buf = nullptr;
    uint32_t size = 0;
    void *user_data = nullptr;
};


class TcpConnection : public std::enable_shared_from_this<TcpConnection>
{
public:
    using Sptr = std::shared_ptr<TcpConnection>;
    using WriteCallback =  std::function<void(WriteInfo& )>;

    enum State{
        kConnected = 0,
        kDisconnecting = 1,
        kDisconnected = 2,
    };

private:
    struct WriteReq {
        uv_write_t uv_req;
        uv_buf_t uv_buf;
        WriteCallback cb;
        void *user_data;
        std::shared_ptr<Buffer> buffer;
    };
    using WriteReqSptr = std::shared_ptr<WriteReq>;

public:
    TcpConnection(EventLoop::Var loop, std::shared_ptr<uv_tcp_t> tcp_handle);
    ~TcpConnection();

    void SetConCloseCallback(const ConCloseCallback& cb) { con_close_cb_ = cb; }
    void SetCloseCompleteCallback(const CloseCompleteCallback& cb) { close_complete_cb_ = cb; }
    void SetMessageCallback(const MessageCallback& cb) { message_cb_ = cb; }

    int32_t StartRead();
    int32_t Close();
    int32_t Send(const Buffer::Sptr& buffer, const WriteCallback& cb, void *user);
    int32_t SendNoCopy(const char *data, uint32_t size, const WriteCallback& cb, void *user);

private:
    static void OnAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf);
    static void OnRead(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf);
    static void OnCloseComplete(uv_handle_t *handle);
    static void OnWriteComplete(uv_write_t *req, int32_t status);

    void SetConState(State state) { state_ = state; }

    void OnDisConnect();
    void DoCloseComplete();

    int32_t Write(const WriteReqSptr& req);
    int32_t HandleRead(ssize_t nread);
    int32_t HandleWriteComplete(WriteReq *req, int32_t status);

private:
    EventLoop::Var loop_;
    ConCloseCallback con_close_cb_ = nullptr;
    CloseCompleteCallback close_complete_cb_ = nullptr;
    MessageCallback message_cb_ = nullptr;
    
    std::shared_ptr<uv_tcp_t> tcp_handle_;
    std::shared_ptr<Buffer> read_buffer_;
    std::list<WriteReqSptr> write_reqs_;
    State state_ = kConnected;
};


} //namespace 
} //namespace 